﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKArchUtils.Utils;
using YJKRevitFloorModule.EnumDefine;
using YJKGeometryFuncs;
using YJKRevitView;
using YJKLoopSearch;

namespace YJKRevitFloorModule.Utility
{
	public class UtilityTools
	{
		public static double GetBeamWidthByProfile(FamilyInstance fiBeam)
		{
			return 0.0;
		}

		public static List<UtilityTools.ThicknessOfEdgeInfoEx> GetDocWallBeamCenterCvInfos(ExternalCommandData revit, List<int> lstWallId)
		{
			UtilityTools.m_Revit = revit;
			if (lstWallId != null)
			{
				UtilityTools.m_lstAllWallId.AddRange(lstWallId);
			}
			Document document = revit.Application.ActiveUIDocument.Document;
			List<Element> list = new List<Element>();
			list = new FilteredElementCollector(document).OfClass(typeof(Wall)).ToElements().ToList<Element>();
			list = UtilityTools.FilterWallsSurface(list);


			foreach (Element item in from elem in new FilteredElementCollector(document).OfClass(typeof(FamilyInstance)).ToElements()
			let familyInstance = elem as FamilyInstance
                                     where (int)familyInstance.StructuralType == 1
			select familyInstance)
			{
				list.Add(item);
			}
			List<Pole2D> lstPole2Ds = UtilityTools.CreatePole2DList(list);
			List<UtilityTools.ThicknessOfEdgeInfoEx> result = null;
			try
			{
				result = UtilityTools.TraverseOutAreaInfo(revit, lstPole2Ds);
			}
			catch (Exception)
			{
			}
			return result;
		}

		public static CurveArray GetOffsetCvsLoops(ExternalCommandData m_Revit, List<KeyValuePair<Curve, ElementId>> lstPair, List<UtilityTools.ThicknessOfEdgeInfoEx> lstOutlineEdgeInfos, SearchType searchType, double boundryOffset)
		{
			CurveArray curveArray = new CurveArray();
			Document document = m_Revit.Application.ActiveUIDocument.Document;
			List<Pole2D> list = new List<Pole2D>();
			foreach (KeyValuePair<Curve, ElementId> keyValuePair in lstPair)
			{
				double num = 0.0;
				XYZ ptStart = null;
				XYZ ptEnd = null;
				UtilityTools.ThicknessOfEdgeInfoEx thicknessOfEdgeInfoEx = null;
				bool flag = false;
				bool flag2 = false;
				if (!(document.GetElement(keyValuePair.Value) is Wall))
				{
					flag2 = true;
					flag = true;
				}
				if (!flag)
				{
					UtilityTools.ThicknessOfEdgeInfoEx thicknessOfEdgeInfoEx2 = new UtilityTools.ThicknessOfEdgeInfoEx(keyValuePair.Key, 0.0);
					foreach (UtilityTools.ThicknessOfEdgeInfoEx thicknessOfEdgeInfoEx3 in lstOutlineEdgeInfos)
					{
						XYZ xyz = thicknessOfEdgeInfoEx3.Curve.GetEndPoint(0);
						XYZ xyz2 = thicknessOfEdgeInfoEx3.Curve.GetEndPoint(1);
						if (!xyz.Z.Equals(0.0) || !xyz2.Z.Equals(0.0))
						{
							xyz = new XYZ(xyz.X, xyz.Y, 0.0);
							xyz2 = new XYZ(xyz2.X, xyz2.Y, 0.0);
							if (thicknessOfEdgeInfoEx3.Curve is Line)
							{
								thicknessOfEdgeInfoEx3.Curve = Line.CreateBound(xyz, xyz2);
							}
							else if (thicknessOfEdgeInfoEx3.Curve is Arc)
							{
								XYZ xyz3 = YJKGeometryFuncs.Geometry.CalculatMidPoint(thicknessOfEdgeInfoEx3.Curve as Arc);
								XYZ xyz4 = new XYZ(xyz3.X, xyz3.Y, 0.0);
								thicknessOfEdgeInfoEx3.Curve = Arc.Create(xyz, xyz2, xyz4);
							}
						}
						thicknessOfEdgeInfoEx = thicknessOfEdgeInfoEx3;
						if ((xyz.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.StartPoint) && xyz2.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.EndPoint)) || (xyz.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.EndPoint) && xyz2.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.StartPoint)))
						{
							flag = true;
							if (!keyValuePair.Key.IsCyclic)
							{
								break;
							}
							if (thicknessOfEdgeInfoEx3.Center != null && thicknessOfEdgeInfoEx3.Center.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.Center))
							{
								break;
							}
						}
						else
						{
							if (UtilityTools.m_lstAllWallId.Contains(keyValuePair.Value.IntegerValue))
							{
								flag = true;
								break;
							}
							if (OverlapType.eOverlap == CurveAssistFunc.GetOverlapType(m_Revit.Application, keyValuePair.Key, thicknessOfEdgeInfoEx3.Curve) || OverlapType.e1Cover2 == CurveAssistFunc.GetOverlapType(m_Revit.Application, keyValuePair.Key, thicknessOfEdgeInfoEx3.Curve) || OverlapType.ePartOverlap == CurveAssistFunc.GetOverlapType(m_Revit.Application, keyValuePair.Key, thicknessOfEdgeInfoEx3.Curve) || OverlapType.e2Cover1 == CurveAssistFunc.GetOverlapType(m_Revit.Application, keyValuePair.Key, thicknessOfEdgeInfoEx3.Curve))
							{
								flag = true;
								break;
							}
						}
					}
				}
				if (flag)
				{
					if (searchType == SearchType.ST_OutLoop)
					{
						ptStart = keyValuePair.Key.GetEndPoint(0);
						ptEnd = keyValuePair.Key.GetEndPoint(1);
						if (flag2)
						{
							num = boundryOffset;
						}
						else
						{
							num = thicknessOfEdgeInfoEx.Thickness + boundryOffset;
						}
					}
					else if (searchType == SearchType.ST_Cells)
					{
						ptStart = keyValuePair.Key.GetEndPoint(0);
						ptEnd = keyValuePair.Key.GetEndPoint(1);
						double num2 = 0.0;
						double num3 = 0.0;
						if (flag2)
						{
							num = boundryOffset;
						}
						else if (thicknessOfEdgeInfoEx.Element is Wall)
						{
							foreach (CompoundStructureLayer compoundStructureLayer in (thicknessOfEdgeInfoEx.Element as Wall).WallType.GetCompoundStructure().GetLayers())
							{
								if (1 == (int)compoundStructureLayer.Function)
								{
									num2 = num3;
									break;
								}
								num3 += compoundStructureLayer.Width;
							}
							num = (thicknessOfEdgeInfoEx.Element as Wall).Width / 2.0 - num2;
						}
						else if (thicknessOfEdgeInfoEx.Element is FamilyInstance)
						{
							FamilySymbol symbol = (thicknessOfEdgeInfoEx.Element as FamilyInstance).Symbol;
							if (symbol.GetParameter("b") != null)
							{
								num = symbol.GetParameter("b").AsDouble();
							}
							num /= 2.0;
						}
					}
				}
				else
				{
					ptStart = keyValuePair.Key.GetEndPoint(0);
					ptEnd = keyValuePair.Key.GetEndPoint(1);
				}
				Pole2D item;
				if (keyValuePair.Key.IsCyclic)
				{
					Arc arc = keyValuePair.Key as Arc;
					if (thicknessOfEdgeInfoEx != null)
					{
						item = Pole2D.NewStructure2DPole(thicknessOfEdgeInfoEx.Element.Id, keyValuePair.Key.GetEndPoint(0), keyValuePair.Key.GetEndPoint(1), arc.Center, arc.Normal, num, num);
					}
					else
					{
						item = Pole2D.NewStructure2DPole(null, keyValuePair.Key.GetEndPoint(0), keyValuePair.Key.GetEndPoint(1), arc.Center, arc.Normal, num, num);
					}
				}
				else if (thicknessOfEdgeInfoEx != null)
				{
					item = Pole2D.NewStructure2DPole(thicknessOfEdgeInfoEx.Element.Id, ptStart, ptEnd, num, num);
				}
				else
				{
					item = Pole2D.NewStructure2DPole(null, ptStart, ptEnd, num, num);
				}
				list.Add(item);
			}
			StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(document);
			List<List<ElementId>> list2 = new List<List<ElementId>>();
			foreach (List<Curve> list3 in structureLoopSearcher.GetFullFloorEdgeLoops(list, ref list2, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside))
			{
				foreach (Curve curve in list3)
				{
					curveArray.Append(curve);
				}
			}
			return curveArray;
		}

		public static List<Curve> GetDocFloorProfileCvs(Element floor, FloorEditCommon floorEditCommon)
		{
			List<Curve> list = new List<Curve>();
			List<List<Curve>> list2 = new List<List<Curve>>();
			List<List<Curve>> list3 = new List<List<Curve>>();
			floorEditCommon.GetFloorLoopAndOpeningLoop(floor, ref list2, ref list3);
			if (list2.Count != 0)
			{
				list.AddRange(list2.ElementAt(0));
			}
			return list;
		}

		public static List<Curve> GetSplitCurves(List<Curve> lstCvs)
		{
			List<Curve> result = new List<Curve>();
			List<UtilityTools.CurveData> list = new List<UtilityTools.CurveData>();
			foreach (Curve curve in lstCvs)
			{
				UtilityTools.CurveData curveData = default(UtilityTools.CurveData);
				curveData.m_Curve = curve;
				curveData.m_lstPoints = new List<XYZ>
				{
					curveData.m_Curve.GetEndPoint(0),
					curveData.m_Curve.GetEndPoint(1)
				};
				list.Add(curveData);
			}
			UtilityTools.AllCurvesIntersectionPoint(ref list);
			foreach (UtilityTools.CurveData curveData2 in list)
			{
				curveData2.m_lstPoints.Sort(new DistanceComparer(curveData2.m_Curve.GetEndPoint(0)));
			}
			UtilityTools.DrawCurve(list, ref result);
			return result;
		}

		public static void AllCurvesIntersectionPoint(ref List<UtilityTools.CurveData> lstDatas)
		{
			for (int i = 0; i < lstDatas.Count; i++)
			{
				for (int j = i + 1; j < lstDatas.Count; j++)
				{
					Curve curve = lstDatas[i].m_Curve;
					Curve curve2 = lstDatas[j].m_Curve;
					IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
					curve.Intersect(curve2, out intersectionResultArray);
					if (intersectionResultArray != null)
					{
						for (int k = 0; k < intersectionResultArray.Size; k++)
						{
                            XYZ xyzpoint = intersectionResultArray.get_Item(k).XYZPoint;
							UtilityTools.FilterIntersectionPoint(ref lstDatas, i, xyzpoint);
							UtilityTools.FilterIntersectionPoint(ref lstDatas, j, xyzpoint);
						}
					}
				}
			}
		}

		public static void FilterIntersectionPoint(ref List<UtilityTools.CurveData> lstDatas, int nIndex, XYZ ptPoint)
		{
			if (0 >= lstDatas[nIndex].m_lstPoints.Count)
			{
				return;
			}
			using (List<XYZ>.Enumerator enumerator = lstDatas[nIndex].m_lstPoints.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					if (enumerator.Current.IsAlmostEqualTo(ptPoint))
					{
						return;
					}
				}
			}
			lstDatas[nIndex].m_lstPoints.Add(ptPoint);
		}

		public static void DrawCurve(List<UtilityTools.CurveData> lstDatas, ref List<Curve> lstCurves)
		{
			foreach (UtilityTools.CurveData curveData in lstDatas)
			{
				if (curveData.m_Curve.IsCyclic)
				{
					for (int i = 1; i < curveData.m_lstPoints.Count; i++)
					{
						XYZ xyz = curveData.m_lstPoints[i - 1];
						XYZ xyz2 = curveData.m_lstPoints[i];
						double parameter = curveData.m_Curve.Project(xyz).Parameter;
						double parameter2 = curveData.m_Curve.Project(xyz2).Parameter;
						XYZ xyz3 = curveData.m_Curve.Evaluate((parameter + parameter2) / 2.0, false);
						Arc item = Arc.Create(xyz, xyz2, xyz3);
						lstCurves.Add(item);
					}
				}
				else
				{
					for (int j = 1; j < curveData.m_lstPoints.Count; j++)
					{
						Line item2 = Line.CreateBound(curveData.m_lstPoints[j - 1], curveData.m_lstPoints[j]);
						lstCurves.Add(item2);
					}
				}
			}
		}

		public static ViewPlan GetViewPlanFromName(string strViewPlanName, Autodesk.Revit.DB.Document doc)
		{
			foreach (ViewPlan viewPlan in FloorSelectManager.GetAllFireAreaViewPlan(doc))
			{
				if (viewPlan.Name == strViewPlanName)
				{
					return viewPlan;
				}
			}
			return null;
		}

		public static List<Wall> GetOutWallsCurViewPlan(ViewPlan curViewPlan, Autodesk.Revit.DB.Document doc)
		{
			List<Wall> list = new List<Wall>();
			foreach (RevitLinkInstance revitLinkInstance in Common.GetAllRevitLinkInstancesInDoc(doc))
			{
				Document linkDocument = revitLinkInstance.GetLinkDocument();
				if (linkDocument != null && UtilityTools.GetViewPlanFromName(curViewPlan.Name, linkDocument) != null)
				{
					List<Wall> list2 = new List<Wall>();
					if (list2.Count != 0)
					{
						list.AddRange(list2);
					}
				}
			}
			return list;
		}

		private static List<Pole2D> CreatePole2DList(List<Element> lstElements)
		{
			List<Pole2D> list = new List<Pole2D>();
			foreach (Element element in lstElements)
			{
				Pole2D item = null;
				Curve curve = (element.Location as LocationCurve).Curve;
				if (typeof(Arc) == curve.GetType())
				{
					Arc arc = curve as Arc;
					item = Pole2D.NewStructure2DPole(element.Id, curve.GetEndPoint(0), curve.GetEndPoint(1), arc.Center, arc.Normal, 0.0, 0.0);
				}
				else if (typeof(Line) == curve.GetType())
				{
					item = Pole2D.NewStructure2DPole(element.Id, curve.GetEndPoint(0), curve.GetEndPoint(1), 0.0, 0.0);
				}
				list.Add(item);
			}
			return list;
		}

		private static List<UtilityTools.ThicknessOfEdgeInfoEx> TraverseOutAreaInfo(ExternalCommandData revit, List<Pole2D> lstPole2Ds)
		{
			Document document = revit.Application.ActiveUIDocument.Document;
			List<UtilityTools.ThicknessOfEdgeInfoEx> list = new List<UtilityTools.ThicknessOfEdgeInfoEx>();
			StructureLoopSearcher structureLoopSearcher = new StructureLoopSearcher(revit);
			List<List<Curve>> list2 = null;
			List<List<ElementId>> list3 = new List<List<ElementId>>();
			list2 = structureLoopSearcher.GetFullFloorEdgeLoops(lstPole2Ds, ref list3, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
			for (int i = 0; i < list2.Count; i++)
			{
				for (int j = 0; j < list2[i].Count; j++)
				{
					UtilityTools.ThicknessOfEdgeInfoEx thicknessOfEdgeInfoEx = null;
					Curve cv = list2[i][j];
					ElementId elementId = list3[i][j];
					Element element = document.GetElement(elementId);
					double num = 0.0;
					bool bisSameNormal = false;
					Curve curve = null;
					if (element != null)
					{
						if (typeof(Wall) == element.GetType())
						{
							Wall wall = element as Wall;
							Curve curve2 = (wall.Location as LocationCurve).Curve;
							curve = curve2;
							if (curve2 is Arc)
							{
								XYZ xyz = YJKGeometryFuncs.Geometry.CalculatMidPoint(curve2 as Arc);
								XYZ center = (curve2 as Arc).Center;
								if (YJKRevitTools.GetTwoXYVectorAngle((xyz - center).Normalize(), wall.Orientation.Normalize()) < Math.PI*.5)
								{
									bisSameNormal = true;
								}
							}
							double num2 = 0.0;
							double num3 = 0.0;
							foreach (CompoundStructureLayer compoundStructureLayer in wall.WallType.GetCompoundStructure().GetLayers())
							{
								if (1 == (int)compoundStructureLayer.Function)
								{
									num2 = num3;
									break;
								}
								num3 += compoundStructureLayer.Width;
							}
							thicknessOfEdgeInfoEx = new UtilityTools.ThicknessOfEdgeInfoEx(curve2, 0.0);
							num = wall.Width / 2.0 - num2;
						}
						else if (typeof(FamilyInstance) == element.GetType())
						{
							FamilySymbol symbol = (element as FamilyInstance).Symbol;
							if (symbol.GetParameter("b") != null)
							{
								num = symbol.GetParameter("b").AsDouble();
							}
							thicknessOfEdgeInfoEx = new UtilityTools.ThicknessOfEdgeInfoEx(cv, 0.0);
							num /= 2.0;
						}
						foreach (Pole2D pole2D in lstPole2Ds)
						{
							if ((thicknessOfEdgeInfoEx.StartPoint.IsAlmostEqualTo(pole2D.StartPoint) && thicknessOfEdgeInfoEx.EndPoint.IsAlmostEqualTo(pole2D.EndPoint)) || (thicknessOfEdgeInfoEx.StartPoint.IsAlmostEqualTo(pole2D.EndPoint) && thicknessOfEdgeInfoEx.EndPoint.IsAlmostEqualTo(pole2D.StartPoint)))
							{
								if (!thicknessOfEdgeInfoEx.IsArc)
								{
									thicknessOfEdgeInfoEx.StartPoint = pole2D.StartPoint;
									thicknessOfEdgeInfoEx.EndPoint = pole2D.EndPoint;
									break;
								}
								if (pole2D.Center != null && thicknessOfEdgeInfoEx.Center.IsAlmostEqualTo(pole2D.Center))
								{
									thicknessOfEdgeInfoEx.StartPoint = pole2D.StartPoint;
									thicknessOfEdgeInfoEx.EndPoint = pole2D.EndPoint;
									break;
								}
							}
						}
						thicknessOfEdgeInfoEx.BIsSameNormal = bisSameNormal;
						thicknessOfEdgeInfoEx.Thickness = num;
						thicknessOfEdgeInfoEx.Element = element;
						thicknessOfEdgeInfoEx.Curve = curve;
						list.Add(thicknessOfEdgeInfoEx);
					}
				}
			}
			return list;
		}

		private static List<Element> FilterWallsSurface(List<Element> lstElements)
		{
			List<Element> list = new List<Element>();
			List<WallType> list2 = new List<WallType>();
			foreach (Element element in lstElements)
			{
				bool flag = false;
				bool flag2 = false;
				WallType wallType = (element as Wall).WallType;
				if (wallType != null)
				{
					using (List<WallType>.Enumerator enumerator2 = list2.GetEnumerator())
					{
						while (enumerator2.MoveNext())
						{
							if (enumerator2.Current.Id == wallType.Id)
							{
								flag = true;
								break;
							}
						}
					}
				}
				if (!flag && wallType.GetCompoundStructure() != null)
				{
					foreach (CompoundStructureLayer compoundStructureLayer in wallType.GetCompoundStructure().GetLayers())
					{
						if (1 == (int)compoundStructureLayer.Function)
						{
							flag2 = true;
							break;
						}
					}
					if (flag2)
					{
						list.Add(element);
					}
					else
					{
						list2.Add(wallType);
					}
				}
			}
			return list;
		}

		public static bool FilterWallSurface(Element ele)
		{
			bool result = true;
			if (typeof(Wall) == ele.GetType())
			{
				WallType wallType = (ele as Wall).WallType;
				if (wallType != null)
				{
					if (wallType.GetCompoundStructure() == null)
					{
						return false;
					}
					foreach (CompoundStructureLayer compoundStructureLayer in wallType.GetCompoundStructure().GetLayers())
					{
						if (1 == (int)compoundStructureLayer.Function)
						{
							result = false;
							break;
						}
					}
				}
			}
			return result;
		}

		public static List<KeyValuePair<Curve, double>> CreatePole2DWithThickness(Autodesk.Revit.DB.Document m_Doc, List<Curve> lstCurves, List<UtilityTools.ThicknessOfEdgeInfoEx> lstEdgeInfos)
		{
			new List<Pole2D>();
			new Dictionary<Pole2D, bool>();
			List<KeyValuePair<Curve, double>> list = new List<KeyValuePair<Curve, double>>();
			foreach (Curve curve in lstCurves)
			{
				bool flag = false;
				UtilityTools.ThicknessOfEdgeInfoEx thicknessOfEdgeInfoEx = new UtilityTools.ThicknessOfEdgeInfoEx(curve, 0.0);
				KeyValuePair<Curve, double> item = default(KeyValuePair<Curve, double>);
				foreach (UtilityTools.ThicknessOfEdgeInfoEx thicknessOfEdgeInfoEx2 in lstEdgeInfos)
				{
					if ((thicknessOfEdgeInfoEx.StartPoint.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.StartPoint) && thicknessOfEdgeInfoEx.EndPoint.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.EndPoint)) || (thicknessOfEdgeInfoEx.StartPoint.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.EndPoint) && thicknessOfEdgeInfoEx.EndPoint.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.StartPoint)))
					{
						if (!curve.IsCyclic)
						{
							flag = true;
							item = new KeyValuePair<Curve, double>(curve, thicknessOfEdgeInfoEx2.Thickness);
							break;
						}
						if (thicknessOfEdgeInfoEx2.Center != null && thicknessOfEdgeInfoEx.Center.IsAlmostEqualTo(thicknessOfEdgeInfoEx2.Center))
						{
							flag = true;
							item = new KeyValuePair<Curve, double>(curve, thicknessOfEdgeInfoEx2.Thickness);
							break;
						}
					}
					else if (OverlapType.eOverlap == CurveAssistFunc.GetOverlapType(UtilityTools.m_Revit.Application, curve, thicknessOfEdgeInfoEx2.Curve) || OverlapType.e1Cover2 == CurveAssistFunc.GetOverlapType(UtilityTools.m_Revit.Application, curve, thicknessOfEdgeInfoEx2.Curve) || OverlapType.ePartOverlap == CurveAssistFunc.GetOverlapType(UtilityTools.m_Revit.Application, curve, thicknessOfEdgeInfoEx2.Curve) || OverlapType.e2Cover1 == CurveAssistFunc.GetOverlapType(UtilityTools.m_Revit.Application, curve, thicknessOfEdgeInfoEx2.Curve))
					{
						flag = true;
						item = new KeyValuePair<Curve, double>(curve, thicknessOfEdgeInfoEx2.Thickness);
						break;
					}
				}
				if (!flag)
				{
					item = new KeyValuePair<Curve, double>(curve, 0.0);
				}
				list.Add(item);
			}
			return list;
		}

		private static ExternalCommandData m_Revit = null;

		private static List<int> m_lstAllWallId = new List<int>();

		public struct CurveData
		{
			private CurveData(Curve curve, List<XYZ> lstPoints)
			{
				this.m_Curve = curve;
				this.m_lstPoints = lstPoints;
			}

			public Curve m_Curve;

			public List<XYZ> m_lstPoints;
		}

		public class ThicknessOfEdgeInfoEx : YJKGeometryFuncs.ThicknessOfEdgeInfo, IComparable
		{
			public ThicknessOfEdgeInfoEx(Curve cv, double dThickness = 0.0) : base(cv, dThickness)
			{
			}

			public int CompareTo(object obj)
			{
				throw new NotImplementedException();
			}
		}
	}
}
